/**
 *  Copyright 23.07.2012 oliver.keusemann@googlemail.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package de.xelerity.geolessi.srv.impl.poi.meinestadt;

import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.xelerity.geolessi.preferences.Preferences;
import de.xelerity.geolessi.srv.InfoProvider;
import de.xelerity.geolessi.srv.InfoProvider.HALTESTELLENINFOPROVIDER;
import de.xelerity.geolessi.srv.ServiceProvider;
import de.xelerity.geolessi.srv.haltestelle.LinienProHaltestelleGetterI;
import de.xelerity.geolessi.srv.impl.poi.types.meinestadt.MSClusterItems;
import de.xelerity.geolessi.srv.impl.poi.types.meinestadt.MSItemI;
import de.xelerity.geolessi.srv.impl.poi.types.meinestadt.MSItems;
import de.xelerity.geolessi.srv.impl.poi.types.meinestadt.MSPOI;
import de.xelerity.geolessi.srv.mixed.URLGenerator;
import de.xelerity.geolessi.srv.mixed.WSCallerI;
import de.xelerity.geolessi.srv.poi.HalteStellenAdresseGetterI;
import de.xelerity.geolessi.srv.poi.HalteStellenGetterFacadeI;
import de.xelerity.geolessi.test.Test;
import de.xelerity.geolessi.types.mixed.Koordinate;
import de.xelerity.geolessi.types.mixed.Sector;
import de.xelerity.geolessi.types.poi.HalteStelle;
import de.xelerity.geolessi.types.poi.HalteStellenListe;
import de.xelerity.geolessi.types.poi.HaltestellenIDProvider;
import de.xelerity.geolessi.types.verbindung.Linie;
import de.xelerity.geolessi.types.verbindung.Linien;

public class HalteSellenGetterImpl implements HalteStellenGetterFacadeI {

	private Log log = LogFactory.getLog(HalteSellenGetterImpl.class);

	@Override
	public HalteStellenListe getHalteStellen(Sector S, long pHalteStellenTypen) throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

	public HalteStellenListe getHalteStellen(Koordinate pCenterSearch, long pSearchRadiusM, long pHalteStellenTypen)
			throws Exception {

		if (pHalteStellenTypen == 0 || pHalteStellenTypen < 0) {
			pHalteStellenTypen = HalteStelle.HalteStelleTyp_ALLE;
		}

		String URL = setUpUrl(pCenterSearch, pSearchRadiusM);
		/**
		 * http://stadtplan.meinestadt.de/xml/java-service/poi?amount=9000&category=4&centerY=
		 * 48.731016&clusterRadius=0.00&radiusY=0.009900990099009901&centerX=9.253851&radiusX=
		 * 0.009900990099009901&maxClusterItems=9999&context=poi-service&output=json
		 */
		WSCallerI wsCaller2 = ServiceProvider.getWSCaller();

		if (Preferences.useProxy) {
			wsCaller2.addProperty("PROXYHOST", Preferences.Proxy);
			wsCaller2.addProperty("PROXYPORT", Preferences.ProxyPort + "");
		}

		byte[] callResB = wsCaller2.call(URL);

		String callRes = new String(callResB, "UTF-8");

		ObjectMapper mapper = new ObjectMapper();

		MSPOI poi = mapper.readValue(callRes, MSPOI.class);

		return MSPOIs2HaltestellenListe(poi, pCenterSearch, pSearchRadiusM);

	}

	private void createHalteStelle(HalteStellenListe phalteStellenListe, MSItemI pC) {

		HalteStelle newHalteStelle = new HalteStelle();
		newHalteStelle.setTitle(pC.getTitle());
		newHalteStelle.setKoordinate(new Koordinate(pC.getLatitude(), pC.getLongitude()));
		newHalteStelle.addHaltestellenID(HaltestellenIDProvider.MEINSTADT, pC.getId());

		HalteStellenAdresseGetterI halteStellenAdresseInfoProvider = InfoProvider
				.getHalteStellenAdresseInfoProvider(HALTESTELLENINFOPROVIDER.MEINESTADT);

		String addressInfo = halteStellenAdresseInfoProvider.getAddressInfo(pC.getId());

		newHalteStelle.setAddressbez(addressInfo);
		String bahnHSID = MeineStadtHSID2BahnHSID.getBahnHSID(pC.getId());

		newHalteStelle.addHaltestellenID(HaltestellenIDProvider.BAHN, bahnHSID);

		LinienProHaltestelleGetterI linienProHaltestelleProvider = InfoProvider
				.getLinienProHaltestelleProvider(HALTESTELLENINFOPROVIDER.BAHN);

		Linien linien = null;
		try {
			linien = linienProHaltestelleProvider.getLinien(newHalteStelle.getIDs(HaltestellenIDProvider.BAHN));
		} catch (Exception e) {
			log.error("'LinienProHaltestelleGetterI.getLinien' failed:" + e.getMessage(), e);
			linien = new Linien();
		}

		for (Linie L : linien) {
			long linienTyp = L.getLinienTyp();
			newHalteStelle.addHalteStelleTyp(linienTyp);
		}

		newHalteStelle.setLinien(linien);

		HalteStelle existingHalteStelle = null;
		if (Preferences.DOHSMERGE) {
			existingHalteStelle = phalteStellenListe.halteStelleExists(newHalteStelle);
		}

		// gibt es die HalteStelle schon unter anderer ID?
		if (existingHalteStelle != null) {
			log.info("HS '" + newHalteStelle.getIDDescAsString() + "' exists, merge with: '"
					+ existingHalteStelle.getIDDescAsString() + "'");
			existingHalteStelle.merge(newHalteStelle);
		} else {
			phalteStellenListe.addHalteStelle(newHalteStelle);
		}
	}

	private HalteStellenListe MSPOIs2HaltestellenListe(MSPOI pPOIs, Koordinate pCenterSearch, long pSearchRadiusM) {
		int cnt = 0;
		long distance, maxdis = -1L, mindis = Long.MAX_VALUE;

		HalteStellenListe halteStellenListe = new HalteStellenListe();
		halteStellenListe.setCenterSearch(new Koordinate(pCenterSearch));
		halteStellenListe.setSearchRadiusM(pSearchRadiusM);
		if (pPOIs.getItems() == null) {
			return halteStellenListe;
		}

		for (MSItems I : pPOIs.getItems()) {

			if (I.getClusteritems() != null) {
				List<MSClusterItems> clusteritems = I.getClusteritems();
				for (MSClusterItems C : clusteritems) {
					distance = pCenterSearch.distance(C.getLatitude(), C.getLongitude());
					if (distance > maxdis) {
						maxdis = distance;
					}
					if (distance < mindis) {
						mindis = distance;
					}

					if (distance <= pSearchRadiusM) {
						createHalteStelle(halteStellenListe, (MSItemI) C);
					}
					cnt++;
				}
			} else {

				distance = pCenterSearch.distance(I.getLatitude(), I.getLongitude());
				if (distance > maxdis) {
					maxdis = distance;
				}
				if (distance < mindis) {
					mindis = distance;
				}

				if (distance <= pSearchRadiusM) {
					createHalteStelle(halteStellenListe, (MSItemI) I);
				}
				cnt++;
			}
		}

		log.info("Found '" + cnt + "' Stops in radius '" + pSearchRadiusM + "' of coord: " + pCenterSearch);

		if (Preferences.DOHSCLUSTER) {
			halteStellenListe.cluster();
		}
		halteStellenListe.clean();
		return halteStellenListe;

	}

	private String setUpUrl(Koordinate pCenterSearch, long pSearchRadiusM) throws Exception {
		if (pCenterSearch == null || pCenterSearch.getLatitude() == 0 || pCenterSearch.getLongitude() == 0) {
			throw new IllegalArgumentException("pCenterSearch Koordinate nicht (korrekt) gesetzt");
		}

		URLGenerator urlGenerator = new URLGenerator("stadtplan.meinestadt.de", "xml/java-service/poi");

		urlGenerator.addParameter("output", "json");
		urlGenerator.addParameter("context", "poi-service");

		urlGenerator.addParameter("centerX", (pCenterSearch.getLongitude() + "").replace(',', '.')); // longitude
		urlGenerator.addParameter("centerY", (pCenterSearch.getLatitude() + "").replace(',', '.')); // latitude

		double x = (pSearchRadiusM / 101000.0);
		String xStr = (x + "").replace(',', '.');

		urlGenerator.addParameter("radiusX", xStr);
		urlGenerator.addParameter("radiusY", xStr);
		urlGenerator.addParameter("amount", "9000");
		urlGenerator.addParameter("category", "4"); // Haltestellen
		urlGenerator.addParameter("clusterRadius", "0.00"); // Keine Cluster
		// verwenden (0.25)
		urlGenerator.addParameter("maxClusterItems", "9999");

		return urlGenerator.getURL();

	}

	public static void main(String[] args) {

		Test.startTest();
		HalteSellenGetterImpl halteSellenGetterImpl = new de.xelerity.geolessi.srv.impl.poi.meinestadt.HalteSellenGetterImpl();

		Koordinate pCenterSearch = Koordinate.RUIT;

		try {
			HalteStellenListe halteStellen = halteSellenGetterImpl.getHalteStellen(pCenterSearch, 1000, 0);
			halteStellen.print();

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			Test.endTest();
		}

	}

	@Override
	public HalteStellenListe getHalteStellen(Koordinate pMapCenter, double pSpanX, double pSpanY, long pHalteStellenTypen)
			throws Exception {
		// TODO Auto-generated method stub
		return null;
	}

}
